﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using System.IO.Ports;
using System.Text;

namespace Komodex.NETMF.MicroTweet.SerialConsole
{
    // MicroTweet Serial Console Sample
    // Matt Isenhower, Komodex Systems LLC
    // http://microtweet.codeplex.com

    public class Program
    {
        #region Fields

        protected static SerialPort serialPort = null;
        protected static char[] commandBuffer = new char[255]; // Maximum command length of 255 chars
        protected static int commandBufferPos = 0;
        protected static CommandDelegate CurrentCommandDelegate = null;
        protected static TwitterClient twitterClient = null;

        #endregion

        public static void Main()
        {
            // Initialize TwitterClient
            twitterClient = new TwitterClient(Config.ConsumerKey, Config.ConsumerSecret, Config.UserToken, Config.UserTokenSecret);
            twitterClient.DebugMessage += new DebugMessageEventHandler(twitterClient_DebugMessage);

            // Initialize ports
            serialPort = new SerialPort(Config.SerialPortName, Config.SerialPortBaudRate);
            serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
            serialPort.Open();
            serialPort.WriteLine();
            serialPort.WriteLine();

            // Update the current date/time from an NTP server
            serialPort.Write("Updating date/time... ");
            if (!NTP.UpdateTimeFromNTPServer(Config.NTPServer))
            {
                serialPort.WriteLine("Error. Please check your network connection and NTP server settings.");
                serialPort.Close();
                return;
            }
            serialPort.WriteLine("Done.\r\n");

            // Send initial message
            WriteHelpMessage();
            WriteCursor();

            // Let the interrupts handle everything
            while (true)
                Thread.Sleep(int.MaxValue);
        }

        #region Serial Port

        protected static void WriteHelpMessage()
        {
            serialPort.WriteLine("MicroTweet");
            serialPort.WriteLine("Matt Isenhower, Komodex Systems LLC");
            serialPort.WriteLine("http://microtweet.codeplex.com/");
            serialPort.WriteLine("Running on: " + SystemInfo.OEMString);
            serialPort.WriteLine("Current time: " + DateTime.Now.ToString());
            serialPort.WriteLine();
            serialPort.WriteLine("Commands:");
            serialPort.WriteLine("  ?             Display this help message");
            serialPort.WriteLine("  p [content]   Post a new tweet with the specified content. (If no");
            serialPort.WriteLine("                content is specified, a default tweet will be posted.)");
        }

        protected static void WriteCursor()
        {
            serialPort.Write("> ");
        }

        protected static void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // Assume that sender == serialPort
            // Read the input buffer
            byte[] inputBuf = new byte[serialPort.BytesToRead];
            serialPort.Read(inputBuf, 0, inputBuf.Length);

            // Process each character from the input buffer
            for (int i = 0; i < inputBuf.Length; i++)
                ProcessInputByte(inputBuf[i]);
        }

        static void ProcessInputByte(byte b)
        {
            // Look for special characters
            switch (b)
            {
                case 13: // Newline
                    serialPort.WriteLine();
                    ProcessCommandBuffer();
                    return;

                case 127: // Backspace
                    if (commandBufferPos > 0)
                    {
                        commandBufferPos--;
                        serialPort.Write("\b \b");
                    }
                    return;

                default:
                    break;
            }

            // Look for standard input character range
            if (b >= 32 && b <= 126)
            {
                // Echo the character back to the client
                serialPort.Write(new byte[] { b }, 0, 1);

                // Make sure we don't overflow the buffer
                if (commandBufferPos < commandBuffer.Length)
                {
                    commandBuffer[commandBufferPos] = (char)b;
                    commandBufferPos++;
                }
                else
                {
                    commandBufferPos = 0;
                    serialPort.WriteLine("\r\nCommand too long!\r\n");
                    WriteCursor();
                }
            }
        }

        static void ProcessCommandBuffer()
        {
            string commandString = new string(commandBuffer, 0, commandBufferPos);
            commandBufferPos = 0;

            // If there is a command delegate, send the command buffer to it
            if (CurrentCommandDelegate != null)
            {
                CurrentCommandDelegate(commandString);
                return;
            }
            // Default command processing
            else
            {
                string[] commandParts = commandString.Split(' ');
                switch (commandParts[0])
                {
                    case "?": // Help
                        WriteHelpMessage();
                        break;

                    case "p":
                        if (commandString.Length > 2)
                            PostTweet(commandString.Substring(2).Trim());
                        else
                            PostTweet(null);
                        break;

                    default:
                        serialPort.WriteLine("Command not recognized!");
                        break;
                }
            }

            WriteCursor();
        }

        #endregion

        #region Twitter

        protected static void twitterClient_DebugMessage(object sender, DebugMessageEventArgs e)
        {
            Debug.Print(e.Message);
            serialPort.WriteLine(e.Message);
        }

        protected static void PostTweet(string message)
        {
            if (message == null)
                message = "Hello from a " + SystemInfo.OEMString + "!";

            serialPort.WriteLine("Sending \"" + message + "\"");
            bool tweetSent = twitterClient.SendTweet(message);

            if (tweetSent)
                serialPort.WriteLine("Tweet sent successfully.");
        }

        #endregion

    }

    public delegate void CommandDelegate(string command);
}
